//
//  FengSiriService.m
//  FengSiriDemo
//
//  Created by Feng on 2021/7/26.
//

#import "FengSiriService.h"
#import <IntentsUI/IntentsUI.h>
#import <objc/message.h>

@interface FengSiriService()<INUIAddVoiceShortcutViewControllerDelegate,INUIEditVoiceShortcutViewControllerDelegate>

@property (nonatomic, copy) void(^addCompeletion)(NSUInteger, NSString *); //添加
@property (nonatomic, copy) void(^editCompeletion)(NSUInteger, NSString *, NSString *); //编辑
@property (nonatomic, strong) NSDictionary *jsonInfo;

@end

@implementation FengSiriService

+(instancetype)shareInstance {
    static FengSiriService *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[super allocWithZone:NULL] init];
    });
    return sharedInstance;
}

- (instancetype)init {
    if (self = [super init]) {
    }
    return self;
}

#pragma mark --重写 保证为真正的单列
+ (id) allocWithZone:(struct _NSZone *)zone {
    return [self shareInstance];
}

- (id)copyWithZone:(nullable NSZone *)zone {
    Class selfClass = [self class];
    return [selfClass shareInstance];
}

- (id)mutableCopyWithZone:(nullable NSZone *)zone {
    Class selfClass = [self class];
    return [selfClass shareInstance];
}

#pragma mark --是否使用SiriKit功能
-(void)canUseSiriKitWithCompeletion:(void(^)(BOOL enable))compeletion {
    if (compeletion) {
        if (nil == [FengSiriService shareInstance].sceneIntentClassName || [FengSiriService shareInstance].sceneIntentClassName.length == 0) {
            return compeletion(NO);
        }
        if (@available(iOS 12.0,*)) { //12以上才支持
            return compeletion(NO);
        }
        compeletion(YES);
    }
}

#pragma mark --获取Siri用户授权权限
-(INSiriAuthorizationStatus)getSiriAuthStatus {
    return [INPreferences siriAuthorizationStatus];
}

#pragma mark --打开SiriKit权限
- (void)requestSiriAuthWithCompeletion:(void (^)(INSiriAuthorizationStatus status))compeletion {
    [INPreferences requestSiriAuthorization:compeletion];
}

#pragma mark --获取siri快捷
- (void)getShortcutList:(NSString *)intentType compeletion:(void (^)(NSArray<NSDictionary *> *dic))compeletion {
    if ([intentType isEqualToString:[FengSiriService shareInstance].sceneIntentClassName]) {
        [self getSceneShortcutListCompeletion:compeletion];
    }
}

#pragma mark --添加siri快捷任务
- (void)addSiriShortcut:(NSDictionary *)jsonInfo compeletion:(void (^)(MSLSiriServiceAddResult resultCode, NSString * _Nonnull msg))compeletion {
    
    self.addCompeletion = compeletion;
    _jsonInfo = jsonInfo;
    INShortcut *intentShortcut = [self getINShortcutWithJsonInfo:jsonInfo];
    if (nil == intentShortcut) {
        [self addCallBackWithResultCode:MSLSiriServiceAddResultErrorJsonInfo msg:@"json有误"];
        return;
    }
    [self showSiriKitUIWithShortCut:intentShortcut];
}

#pragma mark --编辑Siri
- (void)editShortcut:(NSDictionary *)jsonInfo compeletion:(void (^)(MSLSiriServiceEditResult resultCode, NSString * _Nonnull msg,  NSString *invocationPhrase))compeletion API_AVAILABLE(ios(12.0)) {
    _jsonInfo = jsonInfo;
    _editCompeletion = compeletion;
    NSString *intentType = jsonInfo[@"intentType"];
    if ([intentType isEqualToString:[FengSiriService shareInstance].sceneIntentClassName]) {
        [self editSceneShortcut:jsonInfo[@"shortcutInfo"] compeletion:compeletion];
    }
}

#pragma mark --用于记录用户操作习惯，生成shortCut(NSUserActivity也可以实现，而且可以自定义UI，参照IntentsUI) （暂未使用）
- (void)donateInteraction:(NSDictionary *)jsonInfo {  //通过Intent也可以实现上述效果，生成ShortCut,该方法可以自定义UI，参照IntentsUI。
    NSString *intentType = jsonInfo[@"intentType"];
    // 根据intentType创建对应的Intent
    NSDictionary *shortcutInfo = jsonInfo[@"shortcutInfo"];
    INIntent *intent = [self getInetntWithType:intentType propertyInfo:shortcutInfo];
    
    //参数中的Intent就是开发者自定义的Intent,在用户的某个操作后初始化，并暴露到设置中的ShortCut中
    INInteraction *interaction = [[INInteraction alloc] initWithIntent:intent response:nil];
    
    if ([intentType isEqualToString:[FengSiriService shareInstance].sceneIntentClassName]) {
        interaction.identifier = [NSString stringWithFormat:@"%@", shortcutInfo[@"sceneId"]];
    }else if ([intentType isEqualToString:@"MSLAirPruControlIntent"]) {
        interaction.identifier = shortcutInfo[@"devCode"];
    }else {// 未适配其他意图类型
        interaction.identifier = @"临时ID，待完善";
    }
    
    ////很重要，暴露ShortCut到设置中
    [interaction donateInteractionWithCompletion:^(NSError * _Nullable error) {
        NSLog(@"%s %d 添加结果：%@",__func__,__LINE__,error);
    }];
}

#pragma mark --移除用户捐赠（有可能添加为shortcut的用户信息），在H5中，删除场景时调用 （暂未使用）
- (void)removeDonation:(NSString *)donationId {
    if (nil != donationId) {
        [INInteraction deleteInteractionsWithIdentifiers:@[donationId] completion:^(NSError * _Nullable error) {
            NSLog(@"%s %d 删除domain结果：%@",__func__,__LINE__,error);
        }];
    }
}

#pragma mark --INUIAddVoiceShortcutViewControllerDelegate （添加）
- (void)addVoiceShortcutViewController:(INUIAddVoiceShortcutViewController *)controller didFinishWithVoiceShortcut:(nullable INVoiceShortcut *)voiceShortcut error:(nullable NSError *)error  API_AVAILABLE(ios(12.0)){
    NSLog(@"%s %d 添加结果：%@",__func__,__LINE__,error);

    NSLog(@"%@", error.localizedDescription);
    NSString *message = error.localizedDescription;
    if (!error) {
        message = @"添加成功";
        [controller dismissViewControllerAnimated:YES completion:^{
        }];
    }
    [self addCallBackWithResultCode:MSLSiriServiceAddResultSuccess msg:message];

}

- (void)addVoiceShortcutViewControllerDidCancel:(INUIAddVoiceShortcutViewController *)controller  API_AVAILABLE(ios(12.0)){
    NSLog(@"%s %d 取消添加",__func__,__LINE__);
    [self addCallBackWithResultCode:MSLSiriServiceAddResultCancel msg:@"取消添加"];
    [controller dismissViewControllerAnimated:YES completion:^{
    }];
}

#pragma mark --INUIEditVoiceShortcutViewControllerDelegate （编辑）
- (void)editVoiceShortcutViewController:(INUIEditVoiceShortcutViewController *)controller didUpdateVoiceShortcut:(nullable INVoiceShortcut *)voiceShortcut error:(nullable NSError *)error  API_AVAILABLE(ios(12.0)){
    NSLog(@"%s %d 编辑结果：%@",__func__,__LINE__,error);

    NSString *msg = error.localizedDescription;
    NSString *invocationPhrase = @"";
    MSLSiriServiceEditResult resultCode = MSLSiriServiceEditResultFailure;
    if (!error) {
        msg = @"编辑成功";
        resultCode = MSLSiriServiceEditResultSuccess;
        invocationPhrase = voiceShortcut.invocationPhrase;
    }
    [self editCallBackWithResultCode:resultCode msg:msg invocationPhrase:invocationPhrase];
    [controller dismissViewControllerAnimated:YES completion:^{

    }];
}

- (void)editVoiceShortcutViewController:(INUIEditVoiceShortcutViewController *)controller didDeleteVoiceShortcutWithIdentifier:(NSUUID *)deletedVoiceShortcutIdentifier  API_AVAILABLE(ios(12.0)){
    NSLog(@"%s %d 删除成功",__func__,__LINE__);
    [self editCallBackWithResultCode:MSLSiriServiceDelResultSuccess msg:@"删除成功" invocationPhrase:@""];
    [controller dismissViewControllerAnimated:YES completion:^{

    }];
}

- (void)editVoiceShortcutViewControllerDidCancel:(INUIEditVoiceShortcutViewController *)controller  API_AVAILABLE(ios(12.0)){
    NSLog(@"%s %d 取消编辑",__func__,__LINE__);
    [self editCallBackWithResultCode:MSLSiriServiceEditResultCancel msg:@"取消编辑" invocationPhrase:@""];
    [controller dismissViewControllerAnimated:YES completion:^{
        
    }];
}

#pragma mark ------------------内部函数
#pragma mark --获取场景shortcut列表 （获取场景列表）
- (void)getSceneShortcutListCompeletion:(void (^)(NSArray<NSDictionary *> * _Nullable))compeletion API_AVAILABLE(ios(12.0)) {
    NSArray *shortcutList = [self getshortCutInetntList];
    NSMutableArray *temp = [NSMutableArray array];
    if (shortcutList.count > 0) {
        Class intentClass = NSClassFromString([FengSiriService shareInstance].sceneIntentClassName);
        for (INVoiceShortcut *shortcut in shortcutList) {
            INIntent *intent = shortcut.shortcut.intent;
            if ([intent isKindOfClass:intentClass]) {
                NSMutableDictionary *shortcutInfo = [NSMutableDictionary dictionary];
                [shortcutInfo setObject:[intent valueForKey:@"sceneId"] forKey:@"sceneId"];
                [shortcutInfo setObject:[intent valueForKey:@"siriId"] forKey:@"siriId"];
                [shortcutInfo setObject:shortcut.invocationPhrase forKey:@"invocationPhrase"];
                [temp addObject:shortcutInfo];
            }
        }
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        if (compeletion) {
            compeletion(temp);
        }
    });
}

#pragma mark --json转INShortcut结构 （添加）
- (INShortcut *)getINShortcutWithJsonInfo:(NSDictionary *)jsonInfo  API_AVAILABLE(ios(12.0)) {
    // 根据intentType创建对应的Intent
    NSString *intentType = jsonInfo[@"intentType"];
    NSDictionary *shortcutInfo = jsonInfo[@"shortcutInfo"];
    INIntent *intent = [self getInetntWithType:intentType propertyInfo:shortcutInfo];
    if (nil == intent) return nil;
    INShortcut *intentShortcut = [[INShortcut alloc] initWithIntent:intent];
    return intentShortcut;
}

#pragma mark --组装任务(意图)指令INIntent（添加）
- (INIntent *)getInetntWithType:(NSString *)intentType propertyInfo:(NSDictionary *)shortcutInfo API_AVAILABLE(ios(12.0)) {
    INIntent *intent;
    SEL selector = NSSelectorFromString(@"mj_objectWithKeyValues:"); //MJExtension接口
    if ([NSClassFromString(intentType) respondsToSelector:selector]) { //runtime调用 不直接固定创建
        intent = ((INIntent * (*)(id, SEL, id))objc_msgSend)(NSClassFromString(intentType), selector, shortcutInfo);
        if (shortcutInfo[@"invocationPhrase"]) {
            intent.suggestedInvocationPhrase = shortcutInfo[@"invocationPhrase"];
        }
        // 注意如果这里设置的图片为空将影响Siri的执行
//        NSString *sceneIcon = [NSString stringWithFormat:@"icon_scene_%@", shortcutInfo[@"sceneIcon"]];
//        INImage *image = [self getImageWithName:sceneIcon];
//        if (image) {
//            [intent setImage:image forParameterNamed:@"sceneId"];
//        }
//        //MSLLog(@"%@", intent);
    }
    
    //  根据场景ID查询已有的意图ID，获取新的意图ID
    NSString *siriId = [self getNextSiriIdWithSceneId:shortcutInfo[@"sceneId"]];
    if (intent ) {
        [intent setValue:siriId forKey:@"siriId"];
    }
    return intent;
}

#pragma mark --获取场景的下一个shortcut的siriId(一个场景可添加多个shortcut) （添加）
- (NSString *)getNextSiriIdWithSceneId:(NSString *)sceneId API_AVAILABLE(ios(12.0)) {
    sceneId = [NSString stringWithFormat:@"%@", sceneId];
    NSString *siriId = @"0";
    NSArray *shortcutList = [self getshortCutInetntList];
    
    // 查找出场景下已有的快捷指令列表
    NSMutableArray *temp = [NSMutableArray array];
    if (shortcutList.count > 0) {
        Class intentClass = NSClassFromString([FengSiriService shareInstance].sceneIntentClassName);
        for (INVoiceShortcut *shortcut in shortcutList) {
            INIntent *intent = shortcut.shortcut.intent;
            if ([intent isKindOfClass:intentClass] &&
                [[intent valueForKey:@"sceneId"] isEqualToString:sceneId]) {
                [temp addObject:intent];
            }
        }
    }
    // 对快捷指令进行排序
    [temp sortUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        NSNumber *siriId1 = @([[obj1 valueForKey:@"siriId"] intValue]);
        NSNumber *siriId2 = @([[obj2 valueForKey:@"siriId"] intValue]);
        return [siriId2 compare:siriId1];
    }];
    
    INIntent *latestIntent = [temp firstObject];
    if (nil != latestIntent) {
        siriId = [NSString stringWithFormat:@"%d", [[latestIntent valueForKey:@"siriId"] intValue]+1]; //最新的siriId是当前siriId最大值+1
    }
    return siriId;
}

#pragma mark --查找当前shortcut并编辑（编辑）
- (void)editSceneShortcut:(NSDictionary *)shortcutInfo compeletion:(void (^)(MSLSiriServiceEditResult, NSString * _Nonnull msg,  NSString *invocationPhrase))compeletion API_AVAILABLE(ios(12.0)) {
    NSString *sceneId = shortcutInfo[@"sceneId"];
    NSString *siriId = [NSString stringWithFormat:@"%@", shortcutInfo[@"siriId"]];
    NSArray *shortcutList = [self getshortCutInetntList];
    BOOL exist = NO;
    INVoiceShortcut *voiceShortcut = nil;
    if (shortcutList.count > 0) {
        for (INVoiceShortcut *shortcut in shortcutList) {
            INIntent *intent = shortcut.shortcut.intent;
            if ([[intent valueForKey:@"sceneId"] isEqualToString:sceneId] &&
                [[intent valueForKey:@"siriId"] isEqualToString:siriId]) {
                exist = YES;
                voiceShortcut = shortcut;
                break;
            }
        }
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        if (exist) {
            [self showSiriKitUIWithShortCut:voiceShortcut];
        }else {
            if (compeletion) {
                compeletion(MSLSiriServiceEditResultFailure, @"编辑失败", @"");
            }
        }
    });
}

#pragma mark --获取shortcut list
- (NSArray<INVoiceShortcut *> *)getshortCutInetntList API_AVAILABLE(ios(12.0)) {
    
    __block NSArray<INVoiceShortcut *> *shortcutList;
    NSCondition *condiction = [[NSCondition alloc] init];
    [condiction lock];

//    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    [[INVoiceShortcutCenter sharedCenter] getAllVoiceShortcutsWithCompletion:^(NSArray<INVoiceShortcut *> * _Nullable voiceShortcuts, NSError * _Nullable error) {
        shortcutList = voiceShortcuts;
//        dispatch_semaphore_signal(sem);
        [condiction signal];
    }];
//    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    [condiction wait];
    [condiction unlock];
    return shortcutList;
}

#pragma mark --Siri页面（编辑和添加）
-(void)showSiriKitUIWithShortCut:(id)shortcut API_AVAILABLE(ios(12.0)){
    UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    if ([shortcut isKindOfClass:[INShortcut class]]) { //添加
        INUIAddVoiceShortcutViewController *shortCutVc = [[INUIAddVoiceShortcutViewController alloc] initWithShortcut:shortcut];
        shortCutVc.delegate = self;
        shortCutVc.modalPresentationStyle = UIModalPresentationFullScreen;
        [rootViewController presentViewController:shortCutVc animated:YES completion:nil];
    }else if ([shortcut isKindOfClass:[INVoiceShortcut class]]) {  //编辑
        INUIEditVoiceShortcutViewController *shortCutVc = [[INUIEditVoiceShortcutViewController alloc] initWithVoiceShortcut:shortcut];
        shortCutVc.delegate = self;
        shortCutVc.modalPresentationStyle = UIModalPresentationFullScreen;
        [rootViewController presentViewController:shortCutVc animated:YES completion:nil];
    }
    else {
        
    }
}

#pragma mark --添加回调
- (void)addCallBackWithResultCode:(NSUInteger)code msg:(NSString *)msg {
    if (_addCompeletion) {
        _addCompeletion(code, msg);
        _addCompeletion = nil;
        _jsonInfo = nil;
    }
}

#pragma mark --编辑回调
- (void)editCallBackWithResultCode:(NSUInteger)code msg:(NSString *)msg invocationPhrase:(NSString *)invocationPhrase {
    if (_editCompeletion) {
        _editCompeletion(code, msg, invocationPhrase);
        _editCompeletion = nil;
        _jsonInfo = nil;
    }
}
@end
